{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "outputs": [],
   "source": [
    "# Hyper Parameters\n",
    "BATCH_SIZE = 64\n",
    "LR_G = 0.0001       # 生成器的学习率\n",
    "LR_D = 0.0001       # 判别器的学习率\n",
    "N_IDEAS = 5         # 生成器作品的调试次数\n",
    "ART_COMPONENTS = 15 # g在画布上的点数\n",
    "PAINT_POINTS = np.vstack([np.linspace(-1, 1, ART_COMPONENTS) for _ in range(BATCH_SIZE)])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 432x288 with 1 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 显示我们的模板图像\n",
    "plt.plot(PAINT_POINTS[0], np.sin(PAINT_POINTS[0] * np.pi), c='#74BCFF', lw=5, label='standard curve')\n",
    "plt.legend(loc='best')\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "outputs": [],
   "source": [
    "def artist_works():     # real target\n",
    "    r = 0.02 * np.random.randn(1, ART_COMPONENTS)\n",
    "    paintings = np.sin(PAINT_POINTS * np.pi ) + r\n",
    "    paintings = torch.from_numpy(paintings).float()\n",
    "    return paintings"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 432x288 with 1 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "r = 0.02 * np.random.randn(1, ART_COMPONENTS)\n",
    "paintings = np.sin(PAINT_POINTS * np.pi) + r\n",
    "plt.plot(PAINT_POINTS[0],paintings[0])\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "outputs": [],
   "source": [
    "G = nn.Sequential(      # Generator\n",
    "    nn.Linear(N_IDEAS, 128),    # 数据来自randn\n",
    "    nn.ReLU(),\n",
    "    nn.Linear(128, ART_COMPONENTS),      # 用这些随机点进行画画\n",
    ")\n",
    "\n",
    "D = nn.Sequential(      # Discriminator\n",
    "    nn.Linear(N_IDEAS, 128),        # 接受来自generator的点\n",
    "    nn.ReLU(),\n",
    "    nn.Linear(128, 1),\n",
    "    nn.Sigmoid(),      #   告诉艺术作品是由艺术家创作的概率\n",
    ")"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "outputs": [
    {
     "ename": "RuntimeError",
     "evalue": "mat1 and mat2 shapes cannot be multiplied (64x15 and 5x128)",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mRuntimeError\u001B[0m                              Traceback (most recent call last)",
      "Input \u001B[1;32mIn [75]\u001B[0m, in \u001B[0;36m<cell line: 8>\u001B[1;34m()\u001B[0m\n\u001B[0;32m     10\u001B[0m G_ideas \u001B[38;5;241m=\u001B[39m torch\u001B[38;5;241m.\u001B[39mrandn(BATCH_SIZE, N_IDEAS) \u001B[38;5;66;03m# random ideas\u001B[39;00m\n\u001B[0;32m     11\u001B[0m G_paintings \u001B[38;5;241m=\u001B[39m G(G_ideas)                   \u001B[38;5;66;03m# fake painting from G (random ideas)\u001B[39;00m\n\u001B[1;32m---> 13\u001B[0m prob_artist0 \u001B[38;5;241m=\u001B[39m \u001B[43mD\u001B[49m\u001B[43m(\u001B[49m\u001B[43martist_paintings\u001B[49m\u001B[43m)\u001B[49m         \u001B[38;5;66;03m# D try to increase this prob\u001B[39;00m\n\u001B[0;32m     14\u001B[0m prob_artist1 \u001B[38;5;241m=\u001B[39m D(G_paintings)              \u001B[38;5;66;03m# D try to reduce this prob\u001B[39;00m\n\u001B[0;32m     16\u001B[0m D_loss \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m-\u001B[39m torch\u001B[38;5;241m.\u001B[39mmean(torch\u001B[38;5;241m.\u001B[39mlog(prob_artist0) \u001B[38;5;241m+\u001B[39m torch\u001B[38;5;241m.\u001B[39mlog(\u001B[38;5;241m1.\u001B[39m \u001B[38;5;241m-\u001B[39m prob_artist1))\n",
      "File \u001B[1;32mF:\\Anacond\\Anaconda3\\envs\\pytorch\\lib\\site-packages\\torch\\nn\\modules\\module.py:1110\u001B[0m, in \u001B[0;36mModule._call_impl\u001B[1;34m(self, *input, **kwargs)\u001B[0m\n\u001B[0;32m   1106\u001B[0m \u001B[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001B[39;00m\n\u001B[0;32m   1107\u001B[0m \u001B[38;5;66;03m# this function, and just call forward.\u001B[39;00m\n\u001B[0;32m   1108\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m (\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_backward_hooks \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_forward_hooks \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_forward_pre_hooks \u001B[38;5;129;01mor\u001B[39;00m _global_backward_hooks\n\u001B[0;32m   1109\u001B[0m         \u001B[38;5;129;01mor\u001B[39;00m _global_forward_hooks \u001B[38;5;129;01mor\u001B[39;00m _global_forward_pre_hooks):\n\u001B[1;32m-> 1110\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m forward_call(\u001B[38;5;241m*\u001B[39m\u001B[38;5;28minput\u001B[39m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m   1111\u001B[0m \u001B[38;5;66;03m# Do not call functions when jit is used\u001B[39;00m\n\u001B[0;32m   1112\u001B[0m full_backward_hooks, non_full_backward_hooks \u001B[38;5;241m=\u001B[39m [], []\n",
      "File \u001B[1;32mF:\\Anacond\\Anaconda3\\envs\\pytorch\\lib\\site-packages\\torch\\nn\\modules\\container.py:141\u001B[0m, in \u001B[0;36mSequential.forward\u001B[1;34m(self, input)\u001B[0m\n\u001B[0;32m    139\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mforward\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;28minput\u001B[39m):\n\u001B[0;32m    140\u001B[0m     \u001B[38;5;28;01mfor\u001B[39;00m module \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m:\n\u001B[1;32m--> 141\u001B[0m         \u001B[38;5;28minput\u001B[39m \u001B[38;5;241m=\u001B[39m \u001B[43mmodule\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43minput\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[0;32m    142\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28minput\u001B[39m\n",
      "File \u001B[1;32mF:\\Anacond\\Anaconda3\\envs\\pytorch\\lib\\site-packages\\torch\\nn\\modules\\module.py:1110\u001B[0m, in \u001B[0;36mModule._call_impl\u001B[1;34m(self, *input, **kwargs)\u001B[0m\n\u001B[0;32m   1106\u001B[0m \u001B[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001B[39;00m\n\u001B[0;32m   1107\u001B[0m \u001B[38;5;66;03m# this function, and just call forward.\u001B[39;00m\n\u001B[0;32m   1108\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m (\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_backward_hooks \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_forward_hooks \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_forward_pre_hooks \u001B[38;5;129;01mor\u001B[39;00m _global_backward_hooks\n\u001B[0;32m   1109\u001B[0m         \u001B[38;5;129;01mor\u001B[39;00m _global_forward_hooks \u001B[38;5;129;01mor\u001B[39;00m _global_forward_pre_hooks):\n\u001B[1;32m-> 1110\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m forward_call(\u001B[38;5;241m*\u001B[39m\u001B[38;5;28minput\u001B[39m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m   1111\u001B[0m \u001B[38;5;66;03m# Do not call functions when jit is used\u001B[39;00m\n\u001B[0;32m   1112\u001B[0m full_backward_hooks, non_full_backward_hooks \u001B[38;5;241m=\u001B[39m [], []\n",
      "File \u001B[1;32mF:\\Anacond\\Anaconda3\\envs\\pytorch\\lib\\site-packages\\torch\\nn\\modules\\linear.py:103\u001B[0m, in \u001B[0;36mLinear.forward\u001B[1;34m(self, input)\u001B[0m\n\u001B[0;32m    102\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mforward\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;28minput\u001B[39m: Tensor) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m Tensor:\n\u001B[1;32m--> 103\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mF\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mlinear\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43minput\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mweight\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mbias\u001B[49m\u001B[43m)\u001B[49m\n",
      "\u001B[1;31mRuntimeError\u001B[0m: mat1 and mat2 shapes cannot be multiplied (64x15 and 5x128)"
     ]
    }
   ],
   "source": [
    "opt_D = torch.optim.Adam(D.parameters(), lr=LR_D)\n",
    "opt_G = torch.optim.Adam(G.parameters(), lr=LR_G)\n",
    "\n",
    "plt.ion()    # something about continuous plotting\n",
    "\n",
    "D_loss_history = []\n",
    "G_loss_history = []\n",
    "for step in range(10000):\n",
    "    artist_paintings = artist_works()          # real painting from artist\n",
    "    G_ideas = torch.randn(BATCH_SIZE, N_IDEAS) # random ideas\n",
    "    G_paintings = G(G_ideas)                   # fake painting from G (random ideas)\n",
    "\n",
    "    prob_artist0 = D(artist_paintings)         # D try to increase this prob\n",
    "    prob_artist1 = D(G_paintings)              # D try to reduce this prob\n",
    "\n",
    "    D_loss = - torch.mean(torch.log(prob_artist0) + torch.log(1. - prob_artist1))\n",
    "    G_loss = torch.mean(torch.log(1. - prob_artist1))\n",
    "\n",
    "    D_loss_history.append(D_loss)\n",
    "    G_loss_history.append(G_loss)\n",
    "\n",
    "    opt_D.zero_grad()\n",
    "    D_loss.backward(retain_graph=True)    # reusing computational graph\n",
    "    opt_D.step()\n",
    "\n",
    "    opt_G.zero_grad()\n",
    "    G_loss.backward()\n",
    "    opt_G.step()\n",
    "\n",
    "    if step % 50 == 0:  # plotting\n",
    "        plt.cla()\n",
    "        plt.plot(PAINT_POINTS[0], G_paintings.data.numpy()[0], c='#4AD631', lw=3, label='Generated painting',)\n",
    "        plt.plot(PAINT_POINTS[0], np.sin(PAINT_POINTS[0] * np.pi), c='#74BCFF', lw=3, label='standard curve')\n",
    "        plt.text(-1, 0.75, 'D accuracy=%.2f (0.5 for D to converge)' % prob_artist0.data.numpy().mean(), fontdict={'size': 8})\n",
    "        plt.text(-1, 0.5, 'D score= %.2f (-1.38 for G to converge)' % -D_loss.data.numpy(), fontdict={'size': 8})\n",
    "        plt.ylim((-1, 1));plt.legend(loc='lower right', fontsize=10);plt.draw();plt.pause(0.01)\n",
    "\n",
    "plt.ioff()\n",
    "plt.show()\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}